/********************************************************************************
 * Project Name		[JavaSE_Fundamentals]
 * File Name     	[ArithmeticOperators.java]
 * Creation Date 	[2015-01-01]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ********************************************************************************/
package basicGrammar.operators;

/**
 * 算数运算符<br/>
 * 
 * +, -, *, /, % <br/>
 * 
 * @author 不落的太阳(Sean Yang aka ShortPeace)
 * @version 1.0
 * @since jdk 1.8
 * 
 */
public class ArithmeticOperators {

	/**
	 * 如果两个操作数中有一个是double类型, 则先将另一个操作数转换为double类型, 然后运算, 否则<br>
	 * 如果两个操作数中有一个是float类型, 则先将另一个操作数转换为float类型, 然后运算, 否则 <br>
	 * 如果两个操作数中有一个是long类型, 则先将另一个操作数转换为long类型, 然后运算, 否则 <br>
	 * 所有的操作数都被转换为int类型进行运算[低于int类型的会自动提升]<br/>
	 */
	public static void arithmeticOperator1() {
		double d1 = 10.0;
		float f1 = 10.0F;
		double result1 = d1 + f1;
		System.out.println("double + float = " + result1);

		float f2 = 10.0F;
		long l1 = 10L;
		float result2 = f2 + l1;
		System.out.println("float + long = " + result2);

		long l2 = 10L;
		int i1 = 10;
		long result3 = l2 + i1;
		System.out.println("long + int = " + result3);
	}

	/**
	 * 加法, 减法和乘法运算产生的结果出现溢出时, 不会出现ArithmeticException, 只会出现精度丢失
	 */
	public static void arithmeticOperator2() {
		int a = 1000;
		int b = 1000;
		System.out.println("a * b = " + a * b);
	}

	/**
	 * 除法运算<br/>
	 * 
	 * 当/号两边数据类型为整型时, 结果为整型<br/>
	 * 当/号两边有一个为浮点型时, 结果为浮点型<br/>
	 * 
	 * 除0<br/>
	 * 左操作数为整型, 右操作数为0, 抛出ArithmeticException<br/>
	 * 左操作数为整型, 右操作数为0.0, 不会抛出异常<br/>
	 * 左操作数为浮点型, 右操作数为0, 不会抛出异常<br/>
	 */
	public static void arithmeticOperator3() {
		int a = 20;
		int b = 5;
		System.out.println("a / b = " + a / b);

		double d1 = 15.0;
		double d2 = 3;
		System.out.println("d1 / d2 = " + d1 / d2);

		System.out.println("2.0 / 0 = " + 2.0 / 0); // Infinity
		System.out.println("-2.0 / 0 = " + -2.0 / 0); // -Infinity
		System.out.println("0.0 / 0 = " + 0.0 / 0); // NaN

		System.out.println("0 / 0.0 is NaN = " + Double.isNaN(0 / 0.0));
	}

	/**
	 * 取余运算<br/>
	 * 
	 * 取余运算的实质是用左操作数连续减去右操作数, 直到相减的结果小于右操作数, 此时结果即为余数<br/>
	 * 取余运算结果的符号取决于左操作数的符号<br/>
	 * 
	 * 对0取余<br/>
	 * 如果左操作数为整型, 右操作数为0, 会抛出ArithmeticException<br/>
	 * 如果左操作数为整型, 右操作数为0.0, 不会抛出异常<br/>
	 * 如果左操作数为浮点型, 右操作数为0, 不会抛出异常<br/>
	 */
	public static void arithmeticOperator4() {
		System.out.println("2.0 % 0 = " + 2.0 % 0); // NaN
		System.out.println("-2.0 % 0 = " + -2.0 % 0); // NaN
		System.out.println("0.0 % 0 = " + 0.0 % 0); // NaN

		System.out.println("0 % 0.0 = " + 0 % 0.0);
	}

	/**
	 * 单操作数<br/>
	 * 
	 * 用"+=", "*="等缩略形式的运算符, 系统会强制将运算结果转换为目标变量类型<br/>
	 * ++, --运算对于byte, short, char类型不会提升数据类型到int, 且运算结果类型也不变<br/>
	 * 取正[+], 取负[-], 取反[~]时, byte, short, char类型会被提升为int类型参与算术运算<br/>
	 * 如果操作数为long或int型, 无论何种单目操作都不会发生类型转换, 且运算结果类型不变<br/>
	 */
	@SuppressWarnings("unused")
	public static void arithmeticOperator5() {
		byte b1 = 10;
		byte b2 = 10;
		// byte b3 = b1 + b2; 编译不通过
		b1 += b2; // 编译通过
		byte b3 = 10 + 10; // 编译通过

		// 后自增在JVM的运行原理:
		// 因为自增之后要使用到没有加一之前的值, 所以JVM会先声明一个临时变量用于保存没有加一之前的值
		int i = 10;
		i = i++;
		System.out.println(i);
		// 上面代码等价于
		// int i = 10;
		// int temp = i;
		// i = temp;
	}

	public static void main(String[] args) {
		arithmeticOperator1();
		arithmeticOperator2();
		arithmeticOperator3();
		arithmeticOperator4();
		arithmeticOperator5();
	}
}
